<!DOCTYPE html>
<html>
<head>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id='UA-133422980-2"></script>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());

	  gtag('config', 'UA-133422980-2');
	</script>

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>
		gem5: Creating SimObjects in the memory system 
	</title>

	<!-- SITE FAVICON -->
	<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>

	<link rel="canonical" href="http://localhost:4000/documentation/learning_gem5/part2/memoryobject/">
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>

	<!-- FAVICON -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

	<!-- BOOTSTRAP -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

	<!-- CUSTOM CSS -->
	<link rel="stylesheet" href="/css/main.css">
</head>


<body>
	<nav class="navbar navbar-expand-md navbar-light bg-light">
  <a class="navbar-brand" href="/">
		<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=55px>
	</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <!-- LIST FOR NAVBAR -->
    <ul class="navbar-nav ml-auto">
      <!-- HOME -->
      <li class="nav-item ">
        <a class="nav-link" href="/">Home</a>
      </li>

      <!-- ABOUT -->
			<li class="nav-item dropdown ">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					About
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="/about">About gem5</a>
          <a class="dropdown-item" href="/publications">Publications</a>
          <a class="dropdown-item" href="/governance">Governance</a>
				</div>
			</li>

      <!-- DOCUMENTATION -->
			<li class="nav-item dropdown active">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					Documentation
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
					<!-- Pull navigation from _data/documentation.yml -->
					
            <a class="dropdown-item" href="/documentation">gem5 documentation</a>
					
            <a class="dropdown-item" href="/documentation/learning_gem5/introduction">Learning gem5</a>
					
            <a class="dropdown-item" href="http://doxygen.gem5.org/release/current/index.html">gem5 Doxygen</a>
					
            <a class="dropdown-item" href="/documentation/reporting_problems">Reporting Problems</a>
					
				</div>
			</li>

      <!-- EVENTS -->
			<li class="nav-item dropdown ">
        <a class="nav-link" href="/events/">Events</a>
			</li>

      <!-- CONTRIBUTING -->
      <li class="nav-item ">
        <a class="nav-link" href="/contributing">Contributing</a>
      </li>

      <!-- BLOG -->
      <li class="nav-item ">
        <a class="nav-link" href="/blog">Blog</a>
      </li>

      <!-- SEARCH -->
			<li class="nav-item ">
        <a class="nav-link" href="/search">Search</a>
      </li>
    </ul>
  </div>
</nav>

	<main>
		<div class="sidenav-top">
  <div class="sidenav-brand bg-light">
    <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="55px"></a>
  </div>
  <div class="search">
    <form action="/search" method="get">
      <!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
      <input type="text" name="query">
      <button type="submit" name="submit"><i class="fa fa-search"></i></button>
    </form>
  </div>
</div>
<div class="sidenav">
  <!-- Pull navigation from _data/documentation.yml -->
  
    
  
    
    
      <a class="item" href="/documentation/learning_gem5/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
        Introduction
      </a>
      <div class="collapse " id="introduction">
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part1" role="button" aria-expanded="false" aria-controls="collapseExample">
        Getting Started
      </a>
      <div class="collapse " id="part1">
        
          <a class="subitem " href="/documentation/learning_gem5/part1/building">Building gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/simple_config">Creating a simple configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/cache_config">Adding cache to configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/gem5_stats">Understanding gem5 statistics and output</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/example_configs">Using the default configuration scripts</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part2" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modifying/Extending
      </a>
      <div class="collapse show" id="part2">
        
          <a class="subitem " href="/documentation/learning_gem5/part2/environment">Setting up your development environment</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/helloobject">Creating a very simple SimObject</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/debugging">Debugging gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/events">Event-driven programming</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/parameters">Adding parameters to SimObjects and more events</a>
        
          <a class="subitem active" href="/documentation/learning_gem5/part2/memoryobject">Creating SimObjects in the memory system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/simplecache">Creating a simple cache object</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part3" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modeling Cache Coherence with Ruby
      </a>
      <div class="collapse " id="part3">
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIintro">Introduction to Ruby</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-intro">MSI example cache protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-declarations">Declaring a state machine</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-in-ports">In port code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-actions">Action code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-transitions">Transition code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/directory">MSI Directory implementation</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIbuilding">Compiling a SLICC protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/configuration">Configuring a simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/running">Running the simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIdebugging">Debugging SLICC Protocols</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/simple-MI_example">Configuring for a standard protocol</a>
        
      </div>
    
      <a class="item" href="/documentation/learning_gem5/gem5_101/" role="button" aria-expanded="false" aria-controls="collapseExample">
        gem5 101
      </a>
      <div class="collapse " id="gem5_101">
        
      </div>
    
    
  
    
  
    
  
</div>


<div class="container" id="doc-container">
  <div class="edit"><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Edit this page</a></div>
  <b>authors:</b> Jason Lowe-Power<br>
  

  <br>
  <h1 id="creating-simobjects-in-the-memory-system">Creating SimObjects in the memory system</h1>

<p>In this chapter, we will create a simple memory object that sits between
the CPU and the memory bus. In the <a href="../simplecache">next chapter</a>
we will take this simple memory object and add some logic to it to make
it a very simple blocking uniprocessor cache.</p>

<h2 id="gem5-master-and-slave-ports">gem5 master and slave ports</h2>

<p>Before diving into the implementation of a memory object, we should
first understand gem5’s master and slave port interface. As previously
discussed in simple-config-chapter, all memory objects are connected
together via ports. These ports provide a rigid interface between these
memory objects.</p>

<p>These ports implement three different memory system <em>modes</em>: timing,
atomic, and functional. The most important mode is <em>timing mode</em>. Timing
mode is the only mode that produces correct simulation results. The
other modes are only used in special circumstances.</p>

<p><em>Atomic mode</em> is useful for fastforwarding simulation to a region of
interest and warming up the simulator. This mode assumes that no events
will be generated in the memory system. Instead, all of the memory
requests execute through a single long callchain. It is not required to
implement atomic accesses for a memory object unless it will be used
during fastforward or during simulator warmup.</p>

<p><em>Functional mode</em> is better described as <em>debugging mode</em>. Functional
mode is used for things like reading data from the host into the
simulator memory. It is used heavily in syscall emulation mode. For
instance, functional mode is used to load the binary in the
<code class="highlighter-rouge">process.cmd</code> from the host into the simulated system’s memory so the
simulated system can access it. Functional accesses should return the
most up-to-date data on a read, no matter where the data is, and should
update all possible valid data on a write (e.g., in a system with caches
there may be multiple valid cache blocks with the same address).</p>

<h3 id="packets">Packets</h3>

<p>In gem5, <code class="highlighter-rouge">Packets</code> are sent across ports. A <code class="highlighter-rouge">Packet</code> is made up of a
<code class="highlighter-rouge">MemReq</code> which is the memory request object. The <code class="highlighter-rouge">MemReq</code> holds
information about the original request that initiated the packet such as
the requestor, the address, and the type of request (read, write, etc.).</p>

<p>Packets also have a <code class="highlighter-rouge">MemCmd</code>, which is the <em>current</em> command of the
packet. This command can change throughout the life of the packet (e.g.,
requests turn into responses once the memory command is satisfied). The
most common <code class="highlighter-rouge">MemCmd</code> are <code class="highlighter-rouge">ReadReq</code> (read request), <code class="highlighter-rouge">ReadResp</code> (read
response), <code class="highlighter-rouge">WriteReq</code> (write request), <code class="highlighter-rouge">WriteResp</code> (write response).
There are also writeback requests (<code class="highlighter-rouge">WritebackDirty</code>, <code class="highlighter-rouge">WritebackClean</code>)
for caches and many other command types.</p>

<p>Packets also either keep the data for the request, or a pointer to the
data. There are options when creating the packet whether the data is
dynamic (explicitly allocated and deallocated), or static (allocated and
deallocated by the packet object).</p>

<p>Finally, packets are used in the classic caches as the unit to track
coherency. Therefore, much of the packet code is specific to the classic
cache coherence protocol. However, packets are used for all
communication between memory objects in gem5, even if they are not
directly involved in coherence (e.g., DRAM controllers and the CPU
models).</p>

<p>All of the port interface functions accept a <code class="highlighter-rouge">Packet</code> pointer as a
parameter. Since this pointer is so common, gem5 includes a typedef for
it: <code class="highlighter-rouge">PacketPtr</code>.</p>

<h3 id="port-interface">Port interface</h3>

<p>There are two types of ports in gem5: master ports and slave ports.
Whenever you implement a memory object, you will implement at least one
of these types of ports. To do this, you create a new class that
inherits from either <code class="highlighter-rouge">MasterPort</code> or <code class="highlighter-rouge">SlavePort</code> for master and slave
ports, respectively. Master ports send requests (and receive response),
and slave ports receive requests (and send responses).</p>

<p>master-slave-1-fig outlines the simplest interaction between a master
and slave port. This figure shows the interaction in timing mode. The
other modes are much simpler and use a simple callchain between the
master and the slave.</p>

<p><img src="/_pages/static/figures/master_slave_1.png" alt="Simple master-slave interaction when both can accept the request and
the response." /></p>

<p>As mentioned above, all of the port interfaces require a <code class="highlighter-rouge">PacketPtr</code> as
a parameter. Each of these functions (<code class="highlighter-rouge">sendTimingReq</code>, <code class="highlighter-rouge">recvTimingReq</code>,
etc.), accepts a single parameter, a <code class="highlighter-rouge">PacketPtr</code>. This packet is the
request or response to send or receive.</p>

<p>To send a request packet, the master calls <code class="highlighter-rouge">sendTimingReq</code>. In turn,
(and in the same callchain), the function <code class="highlighter-rouge">recvTimingReq</code> is called on
the slave with the same <code class="highlighter-rouge">PacketPtr</code> as its sole parameter.</p>

<p>The <code class="highlighter-rouge">recvTimingReq</code> has a return type of <code class="highlighter-rouge">bool</code>. This boolean return
value is directly returned to the calling master. A return value of
<code class="highlighter-rouge">true</code> signifies that the packet was accepted by the slave. A return
value of <code class="highlighter-rouge">false</code>, on the other hand, means that the slave was unable to
accept and the request must be retried sometime in the future.</p>

<p>In master-slave-1-fig, first, the master sends a timing request by
calling <code class="highlighter-rouge">sendTimingReq</code>, which in turn calls <code class="highlighter-rouge">recvTimingResp</code>. The
slave, returns true from <code class="highlighter-rouge">recvTimingResp</code>, which is returned from the
call to <code class="highlighter-rouge">sendTimingReq</code>. The master continue executing, and the slave
does whatever is necessary to complete the request (e.g., if it is a
cache, it looks up the tags to see if there is a match to the address in
the request).</p>

<p>Once the slave completes the request, it can send a response to the
master. The slave calls <code class="highlighter-rouge">sendTimingResp</code> with the response packet (this
should be the same <code class="highlighter-rouge">PacketPtr</code> as the request, but it should now be a
response packet). In turn, the master function <code class="highlighter-rouge">recvTimingResp</code> is
called. The master’s <code class="highlighter-rouge">recvTimingResp</code> function returns <code class="highlighter-rouge">true</code>, which is
the return value of <code class="highlighter-rouge">sendTimingResp</code> in the slave. Thus, the interaction
for that request is complete.</p>

<p>Later in master-slave-example-section we will show the example code for
these functions.</p>

<p>It is possible that the master or slave is busy when they receive a
request or a response. master-slave-2-fig shows the case where the slave
is busy when the original request was sent.</p>

<p><img src="/_pages/static/figures/master_slave_2.png" alt="Simple master-slave interaction when the slave is
busy" /></p>

<p>In this case, the slave returns <code class="highlighter-rouge">false</code> from the <code class="highlighter-rouge">recvTimingReq</code>
function. When a master receives false after calling <code class="highlighter-rouge">sendTimingReq</code>, it
must wait until the its function <code class="highlighter-rouge">recvReqRetry</code> is executed. Only when
this function is called is the master allowed to retry calling
<code class="highlighter-rouge">sendTimingRequest</code>. The above figure shows the timing request failing
once, but it could fail any number of times. Note: it is up to the
master to track the packet that fails, not the slave. The slave <em>does
not</em> keep the pointer to the packet that fails.</p>

<p>Similarly, master-slave-3-fig shows the case when the master is busy at
the time the slave tries to send a response. In this case, the slave
cannot call <code class="highlighter-rouge">sendTimingResp</code> until it receives a <code class="highlighter-rouge">recvRespRetry</code>.</p>

<p><img src="/_pages/static/figures/master_slave_3.png" alt="Simple master-slave interaction when the master is
busy" /></p>

<p>Importantly, in both of these cases, the retry codepath can be a single
call stack. For instance, when the master calls <code class="highlighter-rouge">sendRespRetry</code>,
<code class="highlighter-rouge">recvTimingReq</code> can also be called in the same call stack. Therefore, it
is easy to incorrectly create an infinite recursion bug, or other bugs.
It is important that before a memory object sends a retry, that it is
ready <em>at that instant</em> to accept another packet.</p>

<h2 id="simple-memory-object-example">Simple memory object example</h2>

<p>In this section, we will build a simple memory object. Initially, it
will simply pass requests through from the CPU-side (a simple CPU) to
the memory-side (a simple memory bus). See Figure simple-memobj-figure.
It will have a single master port, to send requests to the memory bus,
and two cpu-side ports for the instruction and data cache ports of the
CPU. In the next chapter &lt;simplecache-chapter&gt;, we will add the logic
to make this object a cache.</p>

<p><img src="/pages/static/figures/simple_memobj.png" alt="System with a simple memory object which sits between a CPU and the
memory bus." /></p>

<h3 id="declare-the-simobject">Declare the SimObject</h3>

<p>Just like when we were creating the simple SimObject in
hello-simobject-chapter, the first step is to create a SimObject Python
file. We will call this simple memory object <code class="highlighter-rouge">SimpleMemobj</code> and create
the SimObject Python file in <code class="highlighter-rouge">src/learning_gem5/simple_memobj</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">m5.params</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">m5.proxy</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">MemObject</span> <span class="kn">import</span> <span class="n">MemObject</span>

<span class="k">class</span> <span class="nc">SimpleMemobj</span><span class="p">(</span><span class="n">MemObject</span><span class="p">):</span>
    <span class="nb">type</span> <span class="o">=</span> <span class="s">'SimpleMemobj'</span>
    <span class="n">cxx_header</span> <span class="o">=</span> <span class="s">"learning_gem5/simple_memobj/simple_memobj.hh"</span>

    <span class="n">inst_port</span> <span class="o">=</span> <span class="n">SlavePort</span><span class="p">(</span><span class="s">"CPU side port, receives requests"</span><span class="p">)</span>
    <span class="n">data_port</span> <span class="o">=</span> <span class="n">SlavePort</span><span class="p">(</span><span class="s">"CPU side port, receives requests"</span><span class="p">)</span>
    <span class="n">mem_side</span> <span class="o">=</span> <span class="n">MasterPort</span><span class="p">(</span><span class="s">"Memory side port, sends requests"</span><span class="p">)</span>
</code></pre></div></div>

<p>For this object, we inherit from <code class="highlighter-rouge">MemObject</code>, not <code class="highlighter-rouge">SimObject</code> since we
are creating an object that will interact with the memory system. The
<code class="highlighter-rouge">MemObject</code> class has two pure virtual functions that we will have to
define in our C++ implementation, <code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code>.</p>

<p>This object’s parameters are three ports. Two ports for the CPU to
connect the instruction and data ports and a port to connect to the
memory bus. These ports do not have a default value, and they have a
simple description.</p>

<p>It is important to remember the names of these ports. We will explicitly
use these names when implementing <code class="highlighter-rouge">SimpleMemobj</code> and defining the
<code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code> functions.</p>

<p>You can download the SimObject file
<a href="/_pages/static/scripts/part2/memoryobject/SimpleMemobj.py">here</a>.</p>

<p>Of course, you also need to create a SConscript file in the new
directory as well that declares the SimObject Python file. You can
download the SConscript file
<a href="/_pages/static/scripts/part2/memoryobject/SConscript">here</a>.</p>

<h3 id="define-the-simplememobj-class">Define the SimpleMemobj class</h3>

<p>Now, we create a header file for <code class="highlighter-rouge">SimpleMemobj</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SimpleMemobj</span> <span class="o">:</span> <span class="k">public</span> <span class="n">MemObject</span>
<span class="p">{</span>
  <span class="nl">private:</span>

  <span class="nl">public:</span>

    <span class="cm">/** constructor
     */</span>
    <span class="n">SimpleMemobj</span><span class="p">(</span><span class="n">SimpleMemobjParams</span> <span class="o">*</span><span class="n">params</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="define-a-slave-port-type">Define a slave port type</h3>

<p>Now, we need to define classes for our two kinds of ports: the CPU-side
and the memory-side ports. For this, we will declare these classes
inside the <code class="highlighter-rouge">SimpleMemobj</code> class since no other object will ever use
these classes.</p>

<p>Let’s start with the slave port, or the CPU-side port. We are going to
inherit from the <code class="highlighter-rouge">SlavePort</code> class. The following is the required code
to override all of the pure virtual functions in the <code class="highlighter-rouge">SlavePort</code> class.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CPUSidePort</span> <span class="o">:</span> <span class="k">public</span> <span class="n">SlavePort</span>
<span class="p">{</span>
  <span class="nl">private:</span>
    <span class="n">SimpleMemobj</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span>

  <span class="nl">public:</span>
    <span class="n">CPUSidePort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">,</span> <span class="n">SimpleMemobj</span> <span class="o">*</span><span class="n">owner</span><span class="p">)</span> <span class="o">:</span>
        <span class="n">SlavePort</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">owner</span><span class="p">),</span> <span class="n">owner</span><span class="p">(</span><span class="n">owner</span><span class="p">)</span>
    <span class="p">{</span> <span class="p">}</span>

    <span class="n">AddrRangeList</span> <span class="n">getAddrRanges</span><span class="p">()</span> <span class="k">const</span> <span class="k">override</span><span class="p">;</span>

  <span class="nl">protected:</span>
    <span class="n">Tick</span> <span class="n">recvAtomic</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span> <span class="k">override</span> <span class="p">{</span> <span class="n">panic</span><span class="p">(</span><span class="s">"recvAtomic unimpl."</span><span class="p">);</span> <span class="p">}</span>
    <span class="kt">void</span> <span class="n">recvFunctional</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span> <span class="k">override</span><span class="p">;</span>
    <span class="kt">bool</span> <span class="n">recvTimingReq</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span> <span class="k">override</span><span class="p">;</span>
    <span class="kt">void</span> <span class="n">recvRespRetry</span><span class="p">()</span> <span class="k">override</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This object requires five functions to be defined.</p>

<p>This object also has a single member variable, its owner, so it can call
functions on that object.</p>

<h3 id="define-a-master-port-type">Define a master port type</h3>

<p>Next, we need to define a master port type. This will be the memory-side
port which will forward request from the CPU-side to the rest of the
memory system.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MemSidePort</span> <span class="o">:</span> <span class="k">public</span> <span class="n">MasterPort</span>
<span class="p">{</span>
  <span class="nl">private:</span>
    <span class="n">SimpleMemobj</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span>

  <span class="nl">public:</span>
    <span class="n">MemSidePort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">,</span> <span class="n">SimpleMemobj</span> <span class="o">*</span><span class="n">owner</span><span class="p">)</span> <span class="o">:</span>
        <span class="n">MasterPort</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">owner</span><span class="p">),</span> <span class="n">owner</span><span class="p">(</span><span class="n">owner</span><span class="p">)</span>
    <span class="p">{</span> <span class="p">}</span>

  <span class="nl">protected:</span>
    <span class="kt">bool</span> <span class="n">recvTimingResp</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span> <span class="k">override</span><span class="p">;</span>
    <span class="kt">void</span> <span class="n">recvReqRetry</span><span class="p">()</span> <span class="k">override</span><span class="p">;</span>
    <span class="kt">void</span> <span class="n">recvRangeChange</span><span class="p">()</span> <span class="k">override</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This class only has three pure virtual functions that we must override.</p>

<h3 id="defining-the-memobject-interface">Defining the MemObject interface</h3>

<p>Now that we have defined these two new types <code class="highlighter-rouge">CPUSidePort</code> and
<code class="highlighter-rouge">MemSidePort</code>, we can declare our three ports as part of <code class="highlighter-rouge">SimpleMemobj</code>.
We also need to declare the two pure virtual functions in the
<code class="highlighter-rouge">MemObject</code> class, <code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code>. These two
functions are used by gem5 during the initialization phase to connect
memory objects together via ports.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SimpleMemobj</span> <span class="o">:</span> <span class="k">public</span> <span class="n">MemObject</span>
<span class="p">{</span>
  <span class="nl">private:</span>

    <span class="o">&lt;</span><span class="n">CPUSidePort</span> <span class="n">declaration</span><span class="o">&gt;</span>
    <span class="o">&lt;</span><span class="n">MemSidePort</span> <span class="n">declaration</span><span class="o">&gt;</span>

    <span class="n">CPUSidePort</span> <span class="n">instPort</span><span class="p">;</span>
    <span class="n">CPUSidePort</span> <span class="n">dataPort</span><span class="p">;</span>

    <span class="n">MemSidePort</span> <span class="n">memPort</span><span class="p">;</span>

  <span class="nl">public:</span>
    <span class="n">SimpleMemobj</span><span class="p">(</span><span class="n">SimpleMemobjParams</span> <span class="o">*</span><span class="n">params</span><span class="p">);</span>

    <span class="n">BaseMasterPort</span><span class="o">&amp;</span> <span class="n">getMasterPort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">if_name</span><span class="p">,</span>
                                  <span class="n">PortID</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">InvalidPortID</span><span class="p">)</span> <span class="k">override</span><span class="p">;</span>

    <span class="n">BaseSlavePort</span><span class="o">&amp;</span> <span class="n">getSlavePort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">if_name</span><span class="p">,</span>
                                <span class="n">PortID</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">InvalidPortID</span><span class="p">)</span> <span class="k">override</span><span class="p">;</span>

<span class="p">};</span>
</code></pre></div></div>

<p>You can download the header file for the <code class="highlighter-rouge">SimpleMemobj</code>
<a href="/_pages/static/scripts/part2/memoryobject/simple_memobj.hh">here</a>.</p>

<h3 id="implementing-basic-memobject-functions">Implementing basic MemObject functions</h3>

<p>For the constructor of <code class="highlighter-rouge">SimpleMemobj</code>, we will simply call the
<code class="highlighter-rouge">MemObject</code> constructor. We also need to initialize all of the ports.
Each port’s constructor takes two parameters: the name and a pointer to
its owner, as we defined in the header file. The name can be any string,
but by convention, it is the same name as in the Python SimObject file.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">SimpleMemobj</span><span class="p">(</span><span class="n">SimpleMemobjParams</span> <span class="o">*</span><span class="n">params</span><span class="p">)</span> <span class="o">:</span>
    <span class="n">MemObject</span><span class="p">(</span><span class="n">params</span><span class="p">),</span>
    <span class="n">instPort</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">+</span> <span class="s">".inst_port"</span><span class="p">,</span> <span class="k">this</span><span class="p">),</span>
    <span class="n">dataPort</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">+</span> <span class="s">".data_port"</span><span class="p">,</span> <span class="k">this</span><span class="p">),</span>
    <span class="n">memPort</span><span class="p">(</span><span class="n">params</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">+</span> <span class="s">".mem_side"</span><span class="p">,</span> <span class="k">this</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we need to implement the interfaces to get the ports. This
interface is made of two functions <code class="highlighter-rouge">getMasterPort</code> and <code class="highlighter-rouge">getSlavePort</code>.
These functions take two parameters. The <code class="highlighter-rouge">if_name</code> is the Python
variable name of the interface for <em>this</em> object. In the case of the
master port it will be <code class="highlighter-rouge">mem_side</code> since this is what we declared as a
<code class="highlighter-rouge">MasterPort</code> in the Python SimObject file.</p>

<p>To implement <code class="highlighter-rouge">getMasterPort</code>, we compare the <code class="highlighter-rouge">if_name</code> and check to see
if it is <code class="highlighter-rouge">mem_side</code> as specified in our Python SimObject file. If it is,
then we return the <code class="highlighter-rouge">memPort</code> object. If not, then we pass the request
name to our parent. However, it will be an error if we try to connect a
slave port to any other named port since the parent class has no ports
defined.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BaseMasterPort</span><span class="o">&amp;</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">getMasterPort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">if_name</span><span class="p">,</span> <span class="n">PortID</span> <span class="n">idx</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">if_name</span> <span class="o">==</span> <span class="s">"mem_side"</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">memPort</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">MemObject</span><span class="o">::</span><span class="n">getMasterPort</span><span class="p">(</span><span class="n">if_name</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To implement <code class="highlighter-rouge">getSlavePort</code>, we similarly check if the <code class="highlighter-rouge">if_name</code> matches
either of the names we defined for our slave ports in the Python
SimObject file. If the name is <code class="highlighter-rouge">"inst_port"</code>, then we return the
instPort, and if the name is <code class="highlighter-rouge">data_port</code> we return the data port.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BaseSlavePort</span><span class="o">&amp;</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">getSlavePort</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">if_name</span><span class="p">,</span> <span class="n">PortID</span> <span class="n">idx</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">if_name</span> <span class="o">==</span> <span class="s">"inst_port"</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">instPort</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">if_name</span> <span class="o">==</span> <span class="s">"data_port"</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">dataPort</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">MemObject</span><span class="o">::</span><span class="n">getSlavePort</span><span class="p">(</span><span class="n">if_name</span><span class="p">,</span> <span class="n">idx</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="implementing-slave-and-master-port-functions">Implementing slave and master port functions</h3>

<p>The implementation of both the slave and master port is relatively
simple. For the most part, each of the port functions just forwards the
information to the main memory object (<code class="highlighter-rouge">SimpleMemobj</code>).</p>

<p>Starting with two simple functions, <code class="highlighter-rouge">getAddrRanges</code> and <code class="highlighter-rouge">recvFunctional</code>
simply call into the <code class="highlighter-rouge">SimpleMemobj</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">AddrRangeList</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">getAddrRanges</span><span class="p">()</span> <span class="k">const</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">owner</span><span class="o">-&gt;</span><span class="n">getAddrRanges</span><span class="p">();</span>
<span class="p">}</span>

<span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">recvFunctional</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">owner</span><span class="o">-&gt;</span><span class="n">handleFunctional</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The implementation of these functions in the <code class="highlighter-rouge">SimpleMemobj</code> are equally
simple. These implementations just pass through the request to the
memory side. We can use <code class="highlighter-rouge">DPRINTF</code> calls here to track what is happening
for debug purposes as well.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">handleFunctional</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">memPort</span><span class="p">.</span><span class="n">sendFunctional</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">AddrRangeList</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">getAddrRanges</span><span class="p">()</span> <span class="k">const</span>
<span class="p">{</span>
    <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleMemobj</span><span class="p">,</span> <span class="s">"Sending new ranges</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">memPort</span><span class="p">.</span><span class="n">getAddrRanges</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Similarly for the <code class="highlighter-rouge">MemSidePort</code>, we need to implement <code class="highlighter-rouge">recvRangeChange</code>
and forward the request through the <code class="highlighter-rouge">SimpleMemobj</code> to the slave port.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">MemSidePort</span><span class="o">::</span><span class="n">recvRangeChange</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">owner</span><span class="o">-&gt;</span><span class="n">sendRangeChange</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">sendRangeChange</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">instPort</span><span class="p">.</span><span class="n">sendRangeChange</span><span class="p">();</span>
    <span class="n">dataPort</span><span class="p">.</span><span class="n">sendRangeChange</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="implementing-receiving-requests">Implementing receiving requests</h3>

<p>The implementation of <code class="highlighter-rouge">recvTimingReq</code> is slightly more complicated. We
need to check to see if the <code class="highlighter-rouge">SimpleMemobj</code> can accept the request. The
<code class="highlighter-rouge">SimpleMemobj</code> is a very simple blocking structure; we only allow a
single request outstanding at a time. Therefore, if we get a request
while another request is outstanding, the <code class="highlighter-rouge">SimpleMemobj</code> will block the
second request.</p>

<p>To simplify the implementation, the <code class="highlighter-rouge">CPUSidePort</code> stores all of the
flow-control information for the port interface. Thus, we need to add an
extra member variable, <code class="highlighter-rouge">needRetry</code>, to the <code class="highlighter-rouge">CPUSidePort</code>, a boolean that
stores whether we need to send a retry whenever the <code class="highlighter-rouge">SimpleMemobj</code>
becomes free. Then, if the <code class="highlighter-rouge">SimpleMemobj</code> is blocked on a request, we
set that we need to send a retry sometime in the future.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">recvTimingReq</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">owner</span><span class="o">-&gt;</span><span class="n">handleRequest</span><span class="p">(</span><span class="n">pkt</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">needRetry</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>To handle the request for the <code class="highlighter-rouge">SimpleMemobj</code>, we first check if the
<code class="highlighter-rouge">SimpleMemobj</code> is already blocked waiting for a response to another
request. If it is blocked, then we return <code class="highlighter-rouge">false</code> to signal the calling
master port that we cannot accept the request right now. Otherwise, we
mark the port as blocked and send the packet out of the memory port. For
this, we can define a helper function in the <code class="highlighter-rouge">MemSidePort</code> object to
hide the flow control from the <code class="highlighter-rouge">SimpleMemobj</code> implementation. We will
assume the <code class="highlighter-rouge">memPort</code> handles all of the flow control and always return
<code class="highlighter-rouge">true</code> from <code class="highlighter-rouge">handleRequest</code> since we were successful in consuming the
request.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">handleRequest</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">blocked</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleMemobj</span><span class="p">,</span> <span class="s">"Got request for addr %#x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">());</span>
    <span class="n">blocked</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">memPort</span><span class="p">.</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we need to implement the <code class="highlighter-rouge">sendPacket</code> function in the
<code class="highlighter-rouge">MemSidePort</code>. This function will handle the flow control in case its
peer slave port cannot accept the request. For this, we need to add a
member to the <code class="highlighter-rouge">MemSidePort</code> to store the packet in case it is blocked.
It is the responsibility of the sender to store the packet if the
receiver cannot receive the request (or response).</p>

<p>This function simply send the packet by calling the function
<code class="highlighter-rouge">sendTimingReq</code>. If the send fails, then this object store the packet in
the <code class="highlighter-rouge">blockedPacket</code> member function so it can send the packet later
(when it receives a <code class="highlighter-rouge">recvReqRetry</code>). This function also contains some
defensive code to make sure there is not a bug and we never try to
overwrite the <code class="highlighter-rouge">blockedPacket</code> variable incorrectly.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">MemSidePort</span><span class="o">::</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">panic_if</span><span class="p">(</span><span class="n">blockedPacket</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="s">"Should never try to send if blocked!"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sendTimingReq</span><span class="p">(</span><span class="n">pkt</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">blockedPacket</span> <span class="o">=</span> <span class="n">pkt</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we need to implement the code to resend the packet. In this
function, we try to resend the packet by calling the <code class="highlighter-rouge">sendPacket</code>
function we wrote above.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">MemSidePort</span><span class="o">::</span><span class="n">recvReqRetry</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">blockedPacket</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">);</span>

    <span class="n">PacketPtr</span> <span class="n">pkt</span> <span class="o">=</span> <span class="n">blockedPacket</span><span class="p">;</span>
    <span class="n">blockedPacket</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>

    <span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="implementing-receiving-responses">Implementing receiving responses</h3>

<p>The response codepath is similar to the receiving codepath. When the
<code class="highlighter-rouge">MemSidePort</code> gets a response, we forward the response through the
<code class="highlighter-rouge">SimpleMemobj</code> to the appropriate <code class="highlighter-rouge">CPUSidePort</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">MemSidePort</span><span class="o">::</span><span class="n">recvTimingResp</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">owner</span><span class="o">-&gt;</span><span class="n">handleResponse</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In the <code class="highlighter-rouge">SimpleMemobj</code>, first, it should always be blocked when we
receive a response since the object is blocking. Before sending the
packet back to the CPU side, we need to mark that the object no longer
blocked. This must be done <em>before calling <code class="highlighter-rouge">sendTimingResp</code></em>. Otherwise,
it is possible to get stuck in an infinite loop as it is possible that
the master port has a single callchain between receiving a response and
sending another request.</p>

<p>After unblocking the <code class="highlighter-rouge">SimpleMemobj</code>, we check to see if the packet is an
instruction or data packet and send it back across the appropriate port.
Finally, since the object is now unblocked, we may need to notify the
CPU side ports that they can now retry their requests that failed.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">handleResponse</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">blocked</span><span class="p">);</span>
    <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleMemobj</span><span class="p">,</span> <span class="s">"Got response for addr %#x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pkt</span><span class="o">-&gt;</span><span class="n">getAddr</span><span class="p">());</span>

    <span class="n">blocked</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

    <span class="c1">// Simply forward to the memory port</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pkt</span><span class="o">-&gt;</span><span class="n">req</span><span class="o">-&gt;</span><span class="n">isInstFetch</span><span class="p">())</span> <span class="p">{</span>
        <span class="n">instPort</span><span class="p">.</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">dataPort</span><span class="p">.</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">instPort</span><span class="p">.</span><span class="n">trySendRetry</span><span class="p">();</span>
    <span class="n">dataPort</span><span class="p">.</span><span class="n">trySendRetry</span><span class="p">();</span>

    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Similar to how we implemented a convenience function for sending packets
in the <code class="highlighter-rouge">MemSidePort</code>, we can implement a <code class="highlighter-rouge">sendPacket</code> function in the
<code class="highlighter-rouge">CPUSidePort</code> to send the responses to the CPU side. This function calls
<code class="highlighter-rouge">sendTimingResp</code> which will in turn call <code class="highlighter-rouge">recvTimingResp</code> on the peer
master port. If this call fails and the peer port is currently blocked,
then we store the packet to be sent later.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">sendPacket</span><span class="p">(</span><span class="n">PacketPtr</span> <span class="n">pkt</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">panic_if</span><span class="p">(</span><span class="n">blockedPacket</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">,</span> <span class="s">"Should never try to send if blocked!"</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">sendTimingResp</span><span class="p">(</span><span class="n">pkt</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">blockedPacket</span> <span class="o">=</span> <span class="n">pkt</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We will send this blocked packet later when we receive a
<code class="highlighter-rouge">recvRespRetry</code>. This function is exactly the same as the <code class="highlighter-rouge">recvReqRetry</code>
above and simply tries to resend the packet, which may be blocked again.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">recvRespRetry</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">assert</span><span class="p">(</span><span class="n">blockedPacket</span> <span class="o">!=</span> <span class="nb">nullptr</span><span class="p">);</span>

    <span class="n">PacketPtr</span> <span class="n">pkt</span> <span class="o">=</span> <span class="n">blockedPacket</span><span class="p">;</span>
    <span class="n">blockedPacket</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>

    <span class="n">sendPacket</span><span class="p">(</span><span class="n">pkt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Finally, we need to implement the extra function <code class="highlighter-rouge">trySendRetry</code> for the
<code class="highlighter-rouge">CPUSidePort</code>. This function is called by the <code class="highlighter-rouge">SimpleMemobj</code> whenever
the <code class="highlighter-rouge">SimpleMemobj</code> may be unblocked. <code class="highlighter-rouge">trySendRetry</code> checks to see if a
retry is needed which we marked in <code class="highlighter-rouge">recvTimingReq</code> whenever the
<code class="highlighter-rouge">SimpleMemobj</code> was blocked on a new request. Then, if the retry is
needed, this function calls <code class="highlighter-rouge">sendRetryReq</code>, which in turn calls
<code class="highlighter-rouge">recvReqRetry</code> on the peer master port (the CPU in this case).</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="n">SimpleMemobj</span><span class="o">::</span><span class="n">CPUSidePort</span><span class="o">::</span><span class="n">trySendRetry</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">needRetry</span> <span class="o">&amp;&amp;</span> <span class="n">blockedPacket</span> <span class="o">==</span> <span class="nb">nullptr</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">needRetry</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
        <span class="n">DPRINTF</span><span class="p">(</span><span class="n">SimpleMemobj</span><span class="p">,</span> <span class="s">"Sending retry req for %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span>
        <span class="n">sendRetryReq</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You can download the implementation for the <code class="highlighter-rouge">SimpleMemobj</code>
<a href="/_pages/static/scripts/part2/memoryobject/simple_memobj.cc">here</a>.</p>

<p>The following figure, memobj-api-figure, shows the relationships between
the <code class="highlighter-rouge">CPUSidePort</code>, <code class="highlighter-rouge">MemSidePort</code>, and <code class="highlighter-rouge">SimpleMemobj</code>. This figure shows
how the peer ports interact with the implementation of the
<code class="highlighter-rouge">SimpleMemobj</code>. Each bold function is one that we had to implement, and
the non-bold functions are the port interfaces to the peer ports. The
colors highlight one API path through the object (e.g., receiving a
request or updating the memory ranges).</p>

<p><img src="/_pages/static/figures/memobj_api.png" alt="Interaction between SimpleMemobj and its ports" /></p>

<p>For this simple memory object, packets are just forwarded from the
CPU-side to the memory side. However, by modifying <code class="highlighter-rouge">handleRequest</code> and
<code class="highlighter-rouge">handleResponse</code>, we can create rich featureful objects, like a cache in
the <a href="../simplecache">next chapter</a>.</p>

<h3 id="create-a-config-file">Create a config file</h3>

<p>This is all of the code needed to implement a simple memory object! In
the <a href="../simplecache">next chapter</a>, we will take this framework
and add some caching logic to make this memory object into a simple
cache. However, before that, let’s look at the config file to add the
SimpleMemobj to your system.</p>

<p>This config file builds off of the simple config file in
simple-config-chapter. However, instead of connecting the CPU directly
to the memory bus, we are going to instantiate a <code class="highlighter-rouge">SimpleMemobj</code> and
place it between the CPU and the memory bus.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">m5</span>
<span class="kn">from</span> <span class="nn">m5.objects</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">system</span> <span class="o">=</span> <span class="n">System</span><span class="p">()</span>
<span class="n">system</span><span class="o">.</span><span class="n">clk_domain</span> <span class="o">=</span> <span class="n">SrcClockDomain</span><span class="p">()</span>
<span class="n">system</span><span class="o">.</span><span class="n">clk_domain</span><span class="o">.</span><span class="n">clock</span> <span class="o">=</span> <span class="s">'1GHz'</span>
<span class="n">system</span><span class="o">.</span><span class="n">clk_domain</span><span class="o">.</span><span class="n">voltage_domain</span> <span class="o">=</span> <span class="n">VoltageDomain</span><span class="p">()</span>
<span class="n">system</span><span class="o">.</span><span class="n">mem_mode</span> <span class="o">=</span> <span class="s">'timing'</span>
<span class="n">system</span><span class="o">.</span><span class="n">mem_ranges</span> <span class="o">=</span> <span class="p">[</span><span class="n">AddrRange</span><span class="p">(</span><span class="s">'512MB'</span><span class="p">)]</span>

<span class="n">system</span><span class="o">.</span><span class="n">cpu</span> <span class="o">=</span> <span class="n">TimingSimpleCPU</span><span class="p">()</span>

<span class="n">system</span><span class="o">.</span><span class="n">memobj</span> <span class="o">=</span> <span class="n">SimpleMemobj</span><span class="p">()</span>

<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">icache_port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">memobj</span><span class="o">.</span><span class="n">inst_port</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">dcache_port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">memobj</span><span class="o">.</span><span class="n">data_port</span>

<span class="n">system</span><span class="o">.</span><span class="n">membus</span> <span class="o">=</span> <span class="n">SystemXBar</span><span class="p">()</span>

<span class="n">system</span><span class="o">.</span><span class="n">memobj</span><span class="o">.</span><span class="n">mem_side</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">slave</span>

<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">createInterruptController</span><span class="p">()</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">interrupts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">pio</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">master</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">interrupts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">int_master</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">slave</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">interrupts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">int_slave</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">master</span>

<span class="n">system</span><span class="o">.</span><span class="n">mem_ctrl</span> <span class="o">=</span> <span class="n">DDR3_1600_8x8</span><span class="p">()</span>
<span class="n">system</span><span class="o">.</span><span class="n">mem_ctrl</span><span class="o">.</span><span class="nb">range</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">mem_ranges</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">system</span><span class="o">.</span><span class="n">mem_ctrl</span><span class="o">.</span><span class="n">port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">master</span>

<span class="n">system</span><span class="o">.</span><span class="n">system_port</span> <span class="o">=</span> <span class="n">system</span><span class="o">.</span><span class="n">membus</span><span class="o">.</span><span class="n">slave</span>

<span class="n">process</span> <span class="o">=</span> <span class="n">Process</span><span class="p">()</span>
<span class="n">process</span><span class="o">.</span><span class="n">cmd</span> <span class="o">=</span> <span class="p">[</span><span class="s">'tests/test-progs/hello/bin/x86/linux/hello'</span><span class="p">]</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">workload</span> <span class="o">=</span> <span class="n">process</span>
<span class="n">system</span><span class="o">.</span><span class="n">cpu</span><span class="o">.</span><span class="n">createThreads</span><span class="p">()</span>

<span class="n">root</span> <span class="o">=</span> <span class="n">Root</span><span class="p">(</span><span class="n">full_system</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">system</span> <span class="o">=</span> <span class="n">system</span><span class="p">)</span>
<span class="n">m5</span><span class="o">.</span><span class="n">instantiate</span><span class="p">()</span>

<span class="k">print</span> <span class="s">"Beginning simulation!"</span>
<span class="n">exit_event</span> <span class="o">=</span> <span class="n">m5</span><span class="o">.</span><span class="n">simulate</span><span class="p">()</span>
<span class="k">print</span> <span class="s">'Exiting @ tick </span><span class="si">%</span><span class="s">i because </span><span class="si">%</span><span class="s">s'</span> <span class="o">%</span> <span class="p">(</span><span class="n">m5</span><span class="o">.</span><span class="n">curTick</span><span class="p">(),</span> <span class="n">exit_event</span><span class="o">.</span><span class="n">getCause</span><span class="p">())</span>
</code></pre></div></div>

<p>You can download this config script
<a href="/_pages/static/scripts/part2/memoryobject/simple_memobj.py">here</a>.</p>

<p>Now, when you run this config file you get the following output.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 compiled Jan  5 2017 13:40:18
gem5 started Jan  9 2017 10:17:17
gem5 executing on chinook, pid 5138
command line: build/X86/gem5.opt configs/learning_gem5/part2/simple_memobj.py

Global frequency set at 1000000000000 ticks per second
warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes)
0: system.remote_gdb.listener: listening for remote gdb #0 on port 7000
warn: CoherentXBar system.membus has no snooping ports attached!
warn: ClockedObject: More than one power state change request encountered within the same simulation tick
Beginning simulation!
info: Entering event queue @ 0.  Starting simulation...
Hello world!
Exiting @ tick 507841000 because target called exit()
</code></pre></div></div>

<p>If you run with the <code class="highlighter-rouge">SimpleMemobj</code> debug flag, you can see all of the
memory requests and responses from and to the CPU.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 compiled Jan  5 2017 13:40:18
gem5 started Jan  9 2017 10:18:51
gem5 executing on chinook, pid 5157
command line: build/X86/gem5.opt --debug-flags=SimpleMemobj configs/learning_gem5/part2/simple_memobj.py

Global frequency set at 1000000000000 ticks per second
Beginning simulation!
info: Entering event queue @ 0.  Starting simulation...
      0: system.memobj: Got request for addr 0x190
  77000: system.memobj: Got response for addr 0x190
  77000: system.memobj: Got request for addr 0x190
 132000: system.memobj: Got response for addr 0x190
 132000: system.memobj: Got request for addr 0x190
 187000: system.memobj: Got response for addr 0x190
 187000: system.memobj: Got request for addr 0x94e30
 250000: system.memobj: Got response for addr 0x94e30
 250000: system.memobj: Got request for addr 0x190
 ...
</code></pre></div></div>

<p>You may also want to change the CPU model to the out-of-order model
(<code class="highlighter-rouge">DerivO3CPU</code>). When using the out-of-order CPU you will potentially see
a different address stream since it allows multiple memory requests
outstanding at a once. When using the out-of-order CPU, there will now
be many stalls because the <code class="highlighter-rouge">SimpleMemobj</code> is blocking.</p>

  <br>

  <!-- RETRIVE PREVIOUS PAGE LINK -->
  
    
  
    
  
    
  
    
  

  <!-- RETRIEVE NEXT PAGE LINK -->
  
    
  
    
  
    
  
    
  


  <div class="navbuttons">
    
      <a href=""><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a>
    

    
      <a href=""><button type="button" class="btn btn-outline-primary">NEXT</button></a>
    
  </div>
</div>

	</main>
	<footer class="page-footer">
	<div class="container">
		<div class="row">

			<div class="col-12 col-sm-4">
				<p>gem5</p>
				<p><a href="/about">About</a></p>
				<p><a href="/publications">Publications</a></p>
				<p><a href="/contributing">Contributing</a></p>
				<p><a href="/governance">Governance</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Docs</p>
				<p><a href="/documentation">Documentation</a></p>
				<p><a href="http://gem5.org/Documentation">Old Documentation</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5">Source</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Help</p>
				<p><a href="/search">Search</a></p>
				<p><a href="/mailing_lists">Mailing Lists</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Website Source</a></p>
			<br></div>

		</div>
	</div>
</footer>


	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
	<script src="https://unpkg.com/commentbox.io/dist/commentBox.min.js"></script>

	<script>
	  // When the user scrolls down 20px from the top of the document, show the button
	  window.onscroll = function() {scrollFunction()};

	  function scrollFunction() {
	      if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
	          document.getElementById("myBtn").style.display = "block";
	      } else {
	          document.getElementById("myBtn").style.display = "none";
	      }
	  }

	  // When the user clicks on the button, scroll to the top of the document
	  function topFunction() {
	      document.body.scrollTop = 0;
	      document.documentElement.scrollTop = 0;
	  }

		import commentBox from 'commentbox.io';
		// or
		const commentBox = require('commentbox.io');
		// or if using the CDN, it will be available as a global "commentBox" variable.

		commentBox('my-project-id');

	</script>

</body>


</html>
